#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from utils.log import log


class BaseAssertion:
    @staticmethod
    def assert_eq(actual_value, expected_value, msg=None):
        """
        equals
        """
        try:
            assert actual_value == expected_value
        except AssertionError as e:
            log.error(f"eq断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_gt(actual_value, expected_value, msg=None):
        """
        greater than
        """
        try:
            assert actual_value > expected_value
        except AssertionError as e:
            log.error(f"gt断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_lt(actual_value, expected_value, msg=None):
        """
        less than
        """
        try:
            assert actual_value < expected_value
        except AssertionError as e:
            log.error(f"lt断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_neq(actual_value, expected_value, msg=None):
        """
        not equals
        """
        try:
            assert actual_value != expected_value
        except AssertionError as e:
            log.error(f"neq断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_ge(actual_value, expected_value, msg=None):
        """
        greater than or equals
        """
        try:
            assert actual_value >= expected_value
        except AssertionError as e:
            log.error(f"ge断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_le(actual_value, expected_value, msg=None):
        """
        less than or equals
        """
        try:
            assert actual_value <= expected_value
        except AssertionError as e:
            log.error(f"le断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}")
            raise e

    @staticmethod
    def assert_contains(actual_value, expected_value, msg=None):
        assert isinstance(
            expected_value, (list, tuple, dict, str, bytes)
        ), "expect_value should be list/tuple/dict/str/bytes type"
        try:
            assert expected_value in actual_value
        except AssertionError as e:
            log.error(
                f"contains断言失败,预期结果:{expected_value},实际结果:{actual_value},断言消息:{msg}"
            )
            raise e

    @staticmethod
    def assert_true(expr, msg=None):
        """
        验证expr是true
        :param expr: 预期值
        :return:
        """
        try:
            assert expr is True
        except AssertionError as e:
            log.error(f"断言失败, 预期值是: True, 实际值是: {expr}, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_false(expr, msg=None):
        """
        验证expr是false
        :param expr:
        :return:
        """
        try:
            assert expr is False
        except AssertionError as e:
            log.error(f"断言失败, 预期值是: False, 实际值是: {expr}, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is(arg1, arg2, msg=None):
        """
        验证arg1、arg2是同一个对象
        :param arg1: 对象1
        :param arg2: 对象2
        :return:
        """
        try:
            assert arg1 is arg2
        except AssertionError as e:
            log.error(f"断言失败, 预期值:{arg2}和实际值:{arg1}不是同一个对象, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is_not(arg1, arg2, msg=None):
        """
        验证arg1、arg2不是同一个对象，是则返回False，否则返回True
        :param arg1: 对象1
        :param arg2: 对象2
        :return:
        """
        try:
            assert arg1 is not arg2
        except AssertionError as e:
            log.error(f"断言失败, 预期值:{arg2}和实际值:{arg1}是同一个对象, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is_none(expr, msg=None):
        """
        验证expr是None
        :param expr:
        :return:
        """
        try:
            assert expr is None
        except AssertionError as e:
            log.error(f"断言失败, 预期值:{expr}不为空, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is_not_none(expr, msg=None):
        """
        验证expr不是None
        :param expr:
        :return:
        """
        try:
            assert expr is not None
        except AssertionError as e:
            log.error(f"断言失败, 预期值:{expr} 为空, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is_null(expr, msg=None):
        """
        验证expr是None
        :param expr:
        :return:
        """
        try:
            assert expr == ""
        except AssertionError as e:
            log.error(f"断言失败, 预期值:{expr} 不为'', 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_is_not_null(expr, msg=None):
        """
        验证expr不是None
        :param expr:
        :return:
        """
        try:
            assert expr != ""
        except AssertionError as e:
            log.error(f"断言失败,  预期值:{expr} 为'', 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_in(arg1, args2, msg=None):
        """
        验证arg1是arg2的子串
        :param arg1:字符串1
        :param arg2:字符串2
        :return:
        """
        try:
            assert arg1 in args2
        except AssertionError as e:
            log.error(f"断言失败, 实际值:{arg1} 不在 预期值:{args2}中, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_not_in(arg1, args2, msg=None):
        """
        验证arg1不是arg2的子串
        :param arg1:字符串1
        :param arg2:字符串2
        :return:
        """
        try:
            assert arg1 not in args2
        except AssertionError as e:
            log.error(f"断言失败, 实际值:{arg1} 在 预期值:{args2}中, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_obj_is_cls_instance(obj, clss, msg=None):
        """
        验证obj是cls的实例
        :param obj:对象
        :param clss:类
        :return:
        """
        try:
            assert isinstance(obj, clss)
        except AssertionError as e:
            log.error(f"断言失败, 实际值：{obj} 不是 预期值：{clss}的实例, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_obj_not_is_cls_instance(obj, clss, msg=None):
        """
        验证obj不是cls的实例
        :param obj:对象
        :param clss:类
        :return:
        """
        try:
            assert not isinstance(obj, clss)
        except AssertionError as e:
            log.error(f"断言失败, 实际值：{obj} 是 预期值：{clss}的实例, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_time(time, expected_time, msg=None):
        """
        验证response body响应时间小于预期最大响应时间,单位：毫秒
        :param time:实际响应时间
        :param expected_time:预期响应时间
        :return:
        """
        try:
            assert time <= expected_time
        except AssertionError as e:
            log.error(f"断言失败, 实际响应时间:{time} 大于 预期响应时间:{expected_time}, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_str_in_obj(arg1: str, arg2: list, msg=None):
        """
        验证字符串在字典的value值中，example: i-ytdmle3i in [{"instnace_id":"i-ytdmle3i"},{"instnace_id":"i-qwerrwesi"}]
        :param arg1: 字符串
        :param arg2: 列表嵌套字典结构
        :return:
        """
        try:
            expected_list = []
            for i in arg2:
                if isinstance(i, dict):
                    for key, value in i.items():
                        expected_list.append(value)
                else:
                    raise ValueError("请确认参数传递是否正确!")
            assert arg1 in expected_list
        except AssertionError as e:
            log.error(f"断言失败,实际值:{arg1} 不在 预期值:{arg2} 中, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_str_not_in_obj(arg1: str, arg2: list, msg=None):
        """
        验证字符串不在字典的value值中，example: i-ytdmle3i in [{"instnace_id":"i-ytdmle3i"},{"instnace_id":"i-qwerrwesi"}]
        :param arg1: 字符串
        :param arg2: 列表嵌套字典结构
        :return:
        """
        try:
            expected_list = []
            for i in arg2:
                for key, value in i.items():
                    expected_list.append(value)
            assert arg1 not in expected_list
        except AssertionError as e:
            log.error(f"断言失败,实际值:{arg1} 在 预期值:{arg2} 中, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_code(response, server_code=0):
        """
        断言实际的业务码是否等于指定的 server_code
        """
        if response is not None:
            ret_code = response.get("ret_code")
            if ret_code is not None:
                BaseAssertion.assert_eq(ret_code, server_code, response)
        else:
            BaseAssertion.assert_is_not_none(response, msg=f"响应数据:{response} 为 None")

    @staticmethod
    def assert_type(actual_value, expected_value, msg=None):
        """
        断言类型是否正确
        :param actual_value: 'abc',123
        :param expected_value: 类型，例如 str、int
        :param msg:
        :return:
        """
        try:
            assert isinstance(actual_value, expected_value)
        except AssertionError as e:
            log.error(f"断言失败, 实际值:{actual_value} 不是 预期值:{expected_value}, 断言消息:{msg}")
            raise e

    @staticmethod
    def assert_lists_eq(actual_value, expected_value, msg=None):
        """
        断言两个列表的值是否相等,不考虑列表顺序
        :param actual_value: 实际值
        :param expected_value: 预期值
        :param msg:
        :return:
        """
        try:
            assert set(actual_value) == set(expected_value)
        except AssertionError as e:
            log.error(f"断言失败, 实际值:{actual_value} 不是 预期值:{expected_value}, 断言消息:{msg}")
            raise e


case_assert = BaseAssertion()
